package com.xinz.protocal.client;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import com.xinz.protocal.Buffer;
import com.xinz.protocal.Serializer;
import com.xinz.protocal.Session;
import com.xinz.protocal.config.ConfigFactory;

/***
 * 远程调用层  RemoteInvoker
 * 序列化层  Serializer
 * 传输层 InvokConnector
 * 
 * 传输层 Connector?
 * 序列化层  Serializer
 * 本地调用层 NativeInvoker
 * 序列化层  Serializer
 * 传输层 Connector?
 * 
 * 传输层 InvokConnector
 * 序列化层  Serializer
 * 远程调用层  RemoteInvoker
 * 
 * @author xingyun
 *
 */
public class RemoteInvoker implements InvocationHandler {
	
	InvokeConnector connector;
	
	Object responseHeader;
	
	ConfigFactory factory;
	
	public RemoteInvoker(RequestHeaderProvider headerProvider, Serializer serializer,
			InvokeConnector connector) {
		super();
//		this.headerProvider = headerProvider;
//		this.serializer = serializer;
//		this.connector = connector;
	}
	
	public RemoteInvoker(ConfigFactory factory, InvokeConnector connector) {
		this.factory = factory;
		this.connector = connector;
	}
	
	@SuppressWarnings("unchecked")
	public <T> T getImplement(Class<T> clazz) {
		if(!clazz.isInterface()) {
			throw new RuntimeException("class" + clazz + "不是一个接口");
		}
		return (T) Proxy.newProxyInstance(RemoteInvoker.class.getClassLoader(), new Class[]{clazz}, this);
	}

	@Override
	public synchronized Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		RequestHeaderProvider provider = factory.getNativeConfig().getRequestHeaderProvider();
		RemoteInvokeListener listener = factory.getNativeConfig().getRemoteInvokeListener();
		Serializer serializer = factory.getShareConfig().getSerializer();
		Session session = connector.getSession();
		Object header = provider.provideRequestHeader(session, method, responseHeader, args);
		listener.onBeginInvoke(method, args);
		Object[] responseHeader = new Object[1];
		// 调用序列化层，把方法调用的细节序列化成字节数组
		try {
			Buffer request = serializer.methodToBuffer(session, method, header, args);
			// 请求服务器
			Buffer resultBuffer = connector.request(request);
			if(resultBuffer == null) {
				listener.onInvokeSuccess(responseHeader[0], null);
				return null;
			}
			Object result;
			result = serializer.parseReturn(session, resultBuffer, responseHeader);
			listener.onInvokeSuccess(responseHeader[0], result);
			// 解析返回结果，如果有异常则直接在解析层抛出
			return result;
		}
		catch(Exception e) {
			listener.onInvokeException(responseHeader[0], e);
			throw e;
		}
		finally {
			this.responseHeader = responseHeader[0];
		}
	}

}
